'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.contextTypes = undefined;

var _objectDestructuringEmpty2 = require('babel-runtime/helpers/objectDestructuringEmpty');

var _objectDestructuringEmpty3 = _interopRequireDefault(_objectDestructuringEmpty2);

var _defineProperty2 = require('babel-runtime/helpers/defineProperty');

var _defineProperty3 = _interopRequireDefault(_defineProperty2);

var _extends2 = require('babel-runtime/helpers/extends');

var _extends3 = _interopRequireDefault(_extends2);

var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');

var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);

var _inherits2 = require('babel-runtime/helpers/inherits');

var _inherits3 = _interopRequireDefault(_inherits2);

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _propTypes = require('prop-types');

var _propTypes2 = _interopRequireDefault(_propTypes);

var _classnames = require('classnames');

var _classnames2 = _interopRequireDefault(_classnames);

var _warning = require('warning');

var _warning2 = _interopRequireDefault(_warning);

var _util = require('./util');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

/**
 * Thought we still use `cloneElement` to pass `key`,
 * other props can pass with context for future refactor.
 */
var contextTypes = exports.contextTypes = {
  rcTree: _propTypes2['default'].shape({
    root: _propTypes2['default'].object,

    prefixCls: _propTypes2['default'].string,
    selectable: _propTypes2['default'].bool,
    showIcon: _propTypes2['default'].bool,
    icon: _propTypes2['default'].oneOfType([_propTypes2['default'].node, _propTypes2['default'].func]),
    draggable: _propTypes2['default'].bool,
    checkable: _propTypes2['default'].oneOfType([_propTypes2['default'].bool, _propTypes2['default'].node]),
    checkStrictly: _propTypes2['default'].bool,
    disabled: _propTypes2['default'].bool,
    openTransitionName: _propTypes2['default'].string,
    openAnimation: _propTypes2['default'].oneOfType([_propTypes2['default'].string, _propTypes2['default'].object]),

    loadData: _propTypes2['default'].func,
    filterTreeNode: _propTypes2['default'].func,
    renderTreeNode: _propTypes2['default'].func,

    isKeyChecked: _propTypes2['default'].func,

    onNodeClick: _propTypes2['default'].func,
    onNodeDoubleClick: _propTypes2['default'].func,
    onNodeExpand: _propTypes2['default'].func,
    onNodeSelect: _propTypes2['default'].func,
    onNodeMouseEnter: _propTypes2['default'].func,
    onNodeMouseLeave: _propTypes2['default'].func,
    onNodeContextMenu: _propTypes2['default'].func,
    onNodeDragStart: _propTypes2['default'].func,
    onNodeDragEnter: _propTypes2['default'].func,
    onNodeDragOver: _propTypes2['default'].func,
    onNodeDragLeave: _propTypes2['default'].func,
    onNodeDragEnd: _propTypes2['default'].func,
    onNodeDrop: _propTypes2['default'].func,
    onBatchNodeCheck: _propTypes2['default'].func,
    onCheckConductFinished: _propTypes2['default'].func
  })
};

var Tree = function (_React$Component) {
  (0, _inherits3['default'])(Tree, _React$Component);

  function Tree(props) {
    (0, _classCallCheck3['default'])(this, Tree);

    var _this = (0, _possibleConstructorReturn3['default'])(this, _React$Component.call(this, props));

    _initialiseProps.call(_this);

    var defaultExpandAll = props.defaultExpandAll,
        defaultExpandParent = props.defaultExpandParent,
        defaultExpandedKeys = props.defaultExpandedKeys,
        defaultCheckedKeys = props.defaultCheckedKeys,
        defaultSelectedKeys = props.defaultSelectedKeys,
        expandedKeys = props.expandedKeys;

    // Sync state with props

    var _ref = (0, _util.calcCheckedKeys)(defaultCheckedKeys, props) || {},
        _ref$checkedKeys = _ref.checkedKeys,
        checkedKeys = _ref$checkedKeys === undefined ? [] : _ref$checkedKeys,
        _ref$halfCheckedKeys = _ref.halfCheckedKeys,
        halfCheckedKeys = _ref$halfCheckedKeys === undefined ? [] : _ref$halfCheckedKeys;

    var state = {
      selectedKeys: (0, _util.calcSelectedKeys)(defaultSelectedKeys, props),
      checkedKeys: checkedKeys,
      halfCheckedKeys: halfCheckedKeys,

      loadedKeys: [],
      loadingKeys: []
    };

    if (defaultExpandAll) {
      state.expandedKeys = (0, _util.getFullKeyList)(props.children);
    } else if (defaultExpandParent) {
      state.expandedKeys = (0, _util.calcExpandedKeys)(expandedKeys || defaultExpandedKeys, props);
    } else {
      state.expandedKeys = defaultExpandedKeys;
    }

    _this.state = (0, _extends3['default'])({}, state, _this.getSyncProps(props) || {});

    // Cache for check status to optimize
    _this.checkedBatch = null;
    return _this;
  }

  Tree.prototype.getChildContext = function getChildContext() {
    var _props = this.props,
        prefixCls = _props.prefixCls,
        selectable = _props.selectable,
        showIcon = _props.showIcon,
        icon = _props.icon,
        draggable = _props.draggable,
        checkable = _props.checkable,
        checkStrictly = _props.checkStrictly,
        disabled = _props.disabled,
        loadData = _props.loadData,
        filterTreeNode = _props.filterTreeNode,
        openTransitionName = _props.openTransitionName,
        openAnimation = _props.openAnimation;

    return {
      rcTree: {
        // root: this,

        prefixCls: prefixCls,
        selectable: selectable,
        showIcon: showIcon,
        icon: icon,
        draggable: draggable,
        checkable: checkable,
        checkStrictly: checkStrictly,
        disabled: disabled,
        openTransitionName: openTransitionName,
        openAnimation: openAnimation,

        loadData: loadData,
        filterTreeNode: filterTreeNode,
        renderTreeNode: this.renderTreeNode,
        isKeyChecked: this.isKeyChecked,

        onNodeClick: this.onNodeClick,
        onNodeDoubleClick: this.onNodeDoubleClick,
        onNodeExpand: this.onNodeExpand,
        onNodeSelect: this.onNodeSelect,
        onNodeLoad: this.onNodeLoad,
        onNodeMouseEnter: this.onNodeMouseEnter,
        onNodeMouseLeave: this.onNodeMouseLeave,
        onNodeContextMenu: this.onNodeContextMenu,
        onNodeDragStart: this.onNodeDragStart,
        onNodeDragEnter: this.onNodeDragEnter,
        onNodeDragOver: this.onNodeDragOver,
        onNodeDragLeave: this.onNodeDragLeave,
        onNodeDragEnd: this.onNodeDragEnd,
        onNodeDrop: this.onNodeDrop,
        onBatchNodeCheck: this.onBatchNodeCheck,
        onCheckConductFinished: this.onCheckConductFinished
      }
    };
  };

  Tree.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
    var _this2 = this;

    // React 16 will not trigger update if new state is null
    this.setState(function (prevState) {
      return _this2.getSyncProps(nextProps, _this2.props, prevState);
    });
  };

  /**
   * [Legacy] Select handler is less small than node,
   * so that this will trigger when drag enter node or select handler.
   * This is a little tricky if customize css without padding.
   * Better for use mouse move event to refresh drag state.
   * But let's just keep it to avoid event trigger logic change.
   */

  /**
   * This will cache node check status to optimize update process.
   * When Tree get trigger `onCheckConductFinished` will flush all the update.
   */

  /**
   * When top `onCheckConductFinished` called, will execute all batch update.
   * And trigger `onCheck` event.
   */

  /**
   * Sync state with props if needed
   */

  /**
   * Only update the value which is not in props
   */

  /**
   * [Legacy] Original logic use `key` as tracking clue.
   * We have to use `cloneElement` to pass `key`.
   */

  Tree.prototype.render = function render() {
    var _this3 = this;

    var _props2 = this.props,
        prefixCls = _props2.prefixCls,
        className = _props2.className,
        focusable = _props2.focusable,
        showLine = _props2.showLine,
        children = _props2.children;

    var domProps = {};

    // [Legacy] Commit: 0117f0c9db0e2956e92cb208f51a42387dfcb3d1
    if (focusable) {
      domProps.tabIndex = '0';
      domProps.onKeyDown = this.onKeyDown;
    }

    return _react2['default'].createElement('ul', (0, _extends3['default'])({}, domProps, {
      className: (0, _classnames2['default'])(prefixCls, className, (0, _defineProperty3['default'])({}, prefixCls + '-show-line', showLine)),
      role: 'tree-node',
      unselectable: 'on'
    }), (0, _util.mapChildren)(children, function (node, index) {
      return _this3.renderTreeNode(node, index);
    }));
  };

  return Tree;
}(_react2['default'].Component);

Tree.propTypes = {
  prefixCls: _propTypes2['default'].string,
  className: _propTypes2['default'].string,
  children: _propTypes2['default'].any,
  showLine: _propTypes2['default'].bool,
  showIcon: _propTypes2['default'].bool,
  icon: _propTypes2['default'].oneOfType([_propTypes2['default'].node, _propTypes2['default'].func]),
  focusable: _propTypes2['default'].bool,
  selectable: _propTypes2['default'].bool,
  disabled: _propTypes2['default'].bool,
  multiple: _propTypes2['default'].bool,
  checkable: _propTypes2['default'].oneOfType([_propTypes2['default'].bool, _propTypes2['default'].node]),
  checkStrictly: _propTypes2['default'].bool,
  draggable: _propTypes2['default'].bool,
  defaultExpandParent: _propTypes2['default'].bool,
  autoExpandParent: _propTypes2['default'].bool,
  defaultExpandAll: _propTypes2['default'].bool,
  defaultExpandedKeys: _propTypes2['default'].arrayOf(_propTypes2['default'].string),
  expandedKeys: _propTypes2['default'].arrayOf(_propTypes2['default'].string),
  defaultCheckedKeys: _propTypes2['default'].arrayOf(_propTypes2['default'].string),
  checkedKeys: _propTypes2['default'].oneOfType([_propTypes2['default'].arrayOf(_propTypes2['default'].string), _propTypes2['default'].object]),
  defaultSelectedKeys: _propTypes2['default'].arrayOf(_propTypes2['default'].string),
  selectedKeys: _propTypes2['default'].arrayOf(_propTypes2['default'].string),
  onClick: _propTypes2['default'].func,
  onDoubleClick: _propTypes2['default'].func,
  onExpand: _propTypes2['default'].func,
  onCheck: _propTypes2['default'].func,
  onSelect: _propTypes2['default'].func,
  onLoad: _propTypes2['default'].func,
  loadData: _propTypes2['default'].func,
  loadedKeys: _propTypes2['default'].arrayOf(_propTypes2['default'].string),
  onMouseEnter: _propTypes2['default'].func,
  onMouseLeave: _propTypes2['default'].func,
  onRightClick: _propTypes2['default'].func,
  onDragStart: _propTypes2['default'].func,
  onDragEnter: _propTypes2['default'].func,
  onDragOver: _propTypes2['default'].func,
  onDragLeave: _propTypes2['default'].func,
  onDragEnd: _propTypes2['default'].func,
  onDrop: _propTypes2['default'].func,
  filterTreeNode: _propTypes2['default'].func,
  openTransitionName: _propTypes2['default'].string,
  openAnimation: _propTypes2['default'].oneOfType([_propTypes2['default'].string, _propTypes2['default'].object])
};
Tree.childContextTypes = contextTypes;
Tree.defaultProps = {
  prefixCls: 'rc-tree',
  showLine: false,
  showIcon: true,
  selectable: true,
  multiple: false,
  checkable: false,
  disabled: false,
  checkStrictly: false,
  draggable: false,
  defaultExpandParent: true,
  autoExpandParent: false,
  defaultExpandAll: false,
  defaultExpandedKeys: [],
  defaultCheckedKeys: [],
  defaultSelectedKeys: []
};

var _initialiseProps = function _initialiseProps() {
  var _this4 = this;

  this.onNodeDragStart = function (event, node) {
    var expandedKeys = _this4.state.expandedKeys;
    var onDragStart = _this4.props.onDragStart;
    var _node$props = node.props,
        eventKey = _node$props.eventKey,
        children = _node$props.children;

    _this4.dragNode = node;

    _this4.setState({
      dragNodesKeys: (0, _util.getDragNodesKeys)(children, node),
      expandedKeys: (0, _util.arrDel)(expandedKeys, eventKey)
    });

    if (onDragStart) {
      onDragStart({ event: event, node: node });
    }
  };

  this.onNodeDragEnter = function (event, node) {
    var expandedKeys = _this4.state.expandedKeys;
    var onDragEnter = _this4.props.onDragEnter;
    var _node$props2 = node.props,
        pos = _node$props2.pos,
        eventKey = _node$props2.eventKey;

    if (!_this4.dragNode) return;

    var dropPosition = (0, _util.calcDropPosition)(event, node);

    // Skip if drag node is self
    if (_this4.dragNode.props.eventKey === eventKey && dropPosition === 0) {
      _this4.setState({
        dragOverNodeKey: '',
        dropPosition: null
      });
      return;
    }

    // Ref: https://github.com/react-component/tree/issues/132
    // Add timeout to let onDragLevel fire before onDragEnter,
    // so that we can clean drag props for onDragLeave node.
    // Macro task for this:
    // https://html.spec.whatwg.org/multipage/webappapis.html#clean-up-after-running-script
    setTimeout(function () {
      // Update drag over node
      _this4.setState({
        dragOverNodeKey: eventKey,
        dropPosition: dropPosition
      });

      // Side effect for delay drag
      if (!_this4.delayedDragEnterLogic) {
        _this4.delayedDragEnterLogic = {};
      }
      Object.keys(_this4.delayedDragEnterLogic).forEach(function (key) {
        clearTimeout(_this4.delayedDragEnterLogic[key]);
      });
      _this4.delayedDragEnterLogic[pos] = setTimeout(function () {
        var newExpandedKeys = (0, _util.arrAdd)(expandedKeys, eventKey);
        _this4.setState({
          expandedKeys: newExpandedKeys
        });

        if (onDragEnter) {
          onDragEnter({ event: event, node: node, expandedKeys: newExpandedKeys });
        }
      }, 400);
    }, 0);
  };

  this.onNodeDragOver = function (event, node) {
    var onDragOver = _this4.props.onDragOver;
    var eventKey = node.props.eventKey;

    // Update drag position

    if (_this4.dragNode && eventKey === _this4.state.dragOverNodeKey) {
      var dropPosition = (0, _util.calcDropPosition)(event, node);

      if (dropPosition === _this4.state.dropPosition) return;

      _this4.setState({
        dropPosition: dropPosition
      });
    }

    if (onDragOver) {
      onDragOver({ event: event, node: node });
    }
  };

  this.onNodeDragLeave = function (event, node) {
    var onDragLeave = _this4.props.onDragLeave;

    _this4.setState({
      dragOverNodeKey: ''
    });

    if (onDragLeave) {
      onDragLeave({ event: event, node: node });
    }
  };

  this.onNodeDragEnd = function (event, node) {
    var onDragEnd = _this4.props.onDragEnd;

    _this4.setState({
      dragOverNodeKey: ''
    });
    if (onDragEnd) {
      onDragEnd({ event: event, node: node });
    }
  };

  this.onNodeDrop = function (event, node) {
    var _state = _this4.state,
        _state$dragNodesKeys = _state.dragNodesKeys,
        dragNodesKeys = _state$dragNodesKeys === undefined ? [] : _state$dragNodesKeys,
        dropPosition = _state.dropPosition;
    var onDrop = _this4.props.onDrop;
    var _node$props3 = node.props,
        eventKey = _node$props3.eventKey,
        pos = _node$props3.pos;

    _this4.setState({
      dragOverNodeKey: '',
      dropNodeKey: eventKey
    });

    if (dragNodesKeys.indexOf(eventKey) !== -1) {
      (0, _warning2['default'])(false, 'Can not drop to dragNode(include it\'s children node)');
      return;
    }

    var posArr = (0, _util.posToArr)(pos);

    var dropResult = {
      event: event,
      node: node,
      dragNode: _this4.dragNode,
      dragNodesKeys: dragNodesKeys.slice(),
      dropPosition: dropPosition + Number(posArr[posArr.length - 1])
    };

    if (dropPosition !== 0) {
      dropResult.dropToGap = true;
    }

    if (onDrop) {
      onDrop(dropResult);
    }
  };

  this.onNodeClick = function (e, treeNode) {
    var onClick = _this4.props.onClick;

    if (onClick) {
      onClick(e, treeNode);
    }
  };

  this.onNodeDoubleClick = function (e, treeNode) {
    var onDoubleClick = _this4.props.onDoubleClick;

    if (onDoubleClick) {
      onDoubleClick(e, treeNode);
    }
  };

  this.onNodeSelect = function (e, treeNode) {
    var selectedKeys = _this4.state.selectedKeys;
    var _props3 = _this4.props,
        onSelect = _props3.onSelect,
        multiple = _props3.multiple,
        children = _props3.children;
    var _treeNode$props = treeNode.props,
        selected = _treeNode$props.selected,
        eventKey = _treeNode$props.eventKey;

    var targetSelected = !selected;

    // Update selected keys
    if (!targetSelected) {
      selectedKeys = (0, _util.arrDel)(selectedKeys, eventKey);
    } else if (!multiple) {
      selectedKeys = [eventKey];
    } else {
      selectedKeys = (0, _util.arrAdd)(selectedKeys, eventKey);
    }

    // [Legacy] Not found related usage in doc or upper libs
    // [Legacy] TODO: add optimize prop to skip node process
    var selectedNodes = [];
    if (selectedKeys.length) {
      (0, _util.traverseTreeNodes)(children, function (_ref2) {
        var node = _ref2.node,
            key = _ref2.key;

        if (selectedKeys.indexOf(key) !== -1) {
          selectedNodes.push(node);
        }
      });
    }

    _this4.setUncontrolledState({ selectedKeys: selectedKeys });

    if (onSelect) {
      var eventObj = {
        event: 'select',
        selected: targetSelected,
        node: treeNode,
        selectedNodes: selectedNodes,
        nativeEvent: e.nativeEvent
      };
      onSelect(selectedKeys, eventObj);
    }
  };

  this.onNodeLoad = function (treeNode) {
    var _props4 = _this4.props,
        loadData = _props4.loadData,
        onLoad = _props4.onLoad;
    var _state2 = _this4.state,
        _state2$loadedKeys = _state2.loadedKeys,
        loadedKeys = _state2$loadedKeys === undefined ? [] : _state2$loadedKeys,
        _state2$loadingKeys = _state2.loadingKeys,
        loadingKeys = _state2$loadingKeys === undefined ? [] : _state2$loadingKeys;
    var eventKey = treeNode.props.eventKey;

    if (!loadData || loadedKeys.indexOf(eventKey) !== -1 || loadingKeys.indexOf(eventKey) !== -1) {
      return null;
    }

    _this4.setState({
      loadingKeys: (0, _util.arrAdd)(loadingKeys, eventKey)
    });
    var promise = loadData(treeNode);
    promise.then(function () {
      var newLoadedKeys = (0, _util.arrAdd)(_this4.state.loadedKeys, eventKey);
      _this4.setUncontrolledState({
        loadedKeys: newLoadedKeys
      });
      _this4.setState({
        loadingKeys: (0, _util.arrDel)(_this4.state.loadingKeys, eventKey)
      });

      if (onLoad) {
        var eventObj = {
          event: 'load',
          node: treeNode
        };
        onLoad(newLoadedKeys, eventObj);
      }
    });

    return promise;
  };

  this.onBatchNodeCheck = function (key, checked, halfChecked, startNode) {
    if (startNode) {
      _this4.checkedBatch = {
        treeNode: startNode,
        checked: checked,
        list: []
      };
    }

    // This code should never called
    if (!_this4.checkedBatch) {
      _this4.checkedBatch = {
        list: []
      };
      (0, _warning2['default'])(false, 'Checked batch not init. This should be a bug. Please fire a issue.');
    }

    _this4.checkedBatch.list.push({ key: key, checked: checked, halfChecked: halfChecked });
  };

  this.onCheckConductFinished = function (e) {
    var _state3 = _this4.state,
        checkedKeys = _state3.checkedKeys,
        halfCheckedKeys = _state3.halfCheckedKeys;
    var _props5 = _this4.props,
        onCheck = _props5.onCheck,
        checkStrictly = _props5.checkStrictly,
        children = _props5.children;

    // Use map to optimize update speed

    var checkedKeySet = {};
    var halfCheckedKeySet = {};

    checkedKeys.forEach(function (key) {
      checkedKeySet[key] = true;
    });
    halfCheckedKeys.forEach(function (key) {
      halfCheckedKeySet[key] = true;
    });

    // Batch process
    _this4.checkedBatch.list.forEach(function (_ref3) {
      var key = _ref3.key,
          checked = _ref3.checked,
          halfChecked = _ref3.halfChecked;

      checkedKeySet[key] = checked;
      halfCheckedKeySet[key] = halfChecked;
    });
    var newCheckedKeys = Object.keys(checkedKeySet).filter(function (key) {
      return checkedKeySet[key];
    });
    var newHalfCheckedKeys = Object.keys(halfCheckedKeySet).filter(function (key) {
      return halfCheckedKeySet[key];
    });

    // Trigger onChecked
    var selectedObj = void 0;

    var eventObj = {
      event: 'check',
      node: _this4.checkedBatch.treeNode,
      checked: _this4.checkedBatch.checked,
      nativeEvent: e.nativeEvent
    };

    if (checkStrictly) {
      selectedObj = (0, _util.getStrictlyValue)(newCheckedKeys, newHalfCheckedKeys);

      // [Legacy] TODO: add optimize prop to skip node process
      eventObj.checkedNodes = [];
      (0, _util.traverseTreeNodes)(children, function (_ref4) {
        var node = _ref4.node,
            key = _ref4.key;

        if (checkedKeySet[key]) {
          eventObj.checkedNodes.push(node);
        }
      });

      _this4.setUncontrolledState({ checkedKeys: newCheckedKeys });
    } else {
      selectedObj = newCheckedKeys;

      // [Legacy] TODO: add optimize prop to skip node process
      eventObj.checkedNodes = [];
      eventObj.checkedNodesPositions = []; // [Legacy] TODO: not in API
      eventObj.halfCheckedKeys = newHalfCheckedKeys; // [Legacy] TODO: not in API
      (0, _util.traverseTreeNodes)(children, function (_ref5) {
        var node = _ref5.node,
            pos = _ref5.pos,
            key = _ref5.key;

        if (checkedKeySet[key]) {
          eventObj.checkedNodes.push(node);
          eventObj.checkedNodesPositions.push({ node: node, pos: pos });
        }
      });

      _this4.setUncontrolledState({
        checkedKeys: newCheckedKeys,
        halfCheckedKeys: newHalfCheckedKeys
      });
    }

    if (onCheck) {
      onCheck(selectedObj, eventObj);
    }

    // Clean up
    _this4.checkedBatch = null;
  };

  this.onNodeExpand = function (e, treeNode) {
    var expandedKeys = _this4.state.expandedKeys;
    var _props6 = _this4.props,
        onExpand = _props6.onExpand,
        loadData = _props6.loadData;
    var _treeNode$props2 = treeNode.props,
        eventKey = _treeNode$props2.eventKey,
        expanded = _treeNode$props2.expanded;

    // Update selected keys

    var index = expandedKeys.indexOf(eventKey);
    var targetExpanded = !expanded;

    (0, _warning2['default'])(expanded && index !== -1 || !expanded && index === -1, 'Expand state not sync with index check');

    if (targetExpanded) {
      expandedKeys = (0, _util.arrAdd)(expandedKeys, eventKey);
    } else {
      expandedKeys = (0, _util.arrDel)(expandedKeys, eventKey);
    }

    _this4.setUncontrolledState({ expandedKeys: expandedKeys });

    if (onExpand) {
      onExpand(expandedKeys, {
        node: treeNode,
        expanded: targetExpanded,
        nativeEvent: e.nativeEvent
      });
    }

    // Async Load data
    if (targetExpanded && loadData) {
      var loadPromise = _this4.onNodeLoad(treeNode);
      return loadPromise ? loadPromise.then(function () {
        // [Legacy] Refresh logic
        _this4.setUncontrolledState({ expandedKeys: expandedKeys });
      }) : null;
    }

    return null;
  };

  this.onNodeMouseEnter = function (event, node) {
    var onMouseEnter = _this4.props.onMouseEnter;

    if (onMouseEnter) {
      onMouseEnter({ event: event, node: node });
    }
  };

  this.onNodeMouseLeave = function (event, node) {
    var onMouseLeave = _this4.props.onMouseLeave;

    if (onMouseLeave) {
      onMouseLeave({ event: event, node: node });
    }
  };

  this.onNodeContextMenu = function (event, node) {
    var onRightClick = _this4.props.onRightClick;

    if (onRightClick) {
      event.preventDefault();
      onRightClick({ event: event, node: node });
    }
  };

  this.getSyncProps = function () {
    var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    var prevProps = arguments[1];
    var preState = arguments[2];

    var needSync = false;
    var oriState = preState || _this4.state;
    var newState = {};
    var myPrevProps = prevProps || {};

    function checkSync(name) {
      if (props[name] !== myPrevProps[name]) {
        needSync = true;
        return true;
      }
      return false;
    }

    // Children change will affect check box status.
    // And no need to check when prev props not provided
    if (prevProps && checkSync('children')) {
      var newCheckedKeys = (0, _util.calcCheckedKeys)(props.checkedKeys || oriState.checkedKeys, props);

      var _ref6 = newCheckedKeys || {},
          _ref6$checkedKeys = _ref6.checkedKeys,
          checkedKeys = _ref6$checkedKeys === undefined ? [] : _ref6$checkedKeys,
          _ref6$halfCheckedKeys = _ref6.halfCheckedKeys,
          halfCheckedKeys = _ref6$halfCheckedKeys === undefined ? [] : _ref6$halfCheckedKeys;

      newState.checkedKeys = checkedKeys;
      newState.halfCheckedKeys = halfCheckedKeys;
    }

    // Re-calculate when autoExpandParent or expandedKeys changed
    if (prevProps && (checkSync('autoExpandParent') || checkSync('expandedKeys'))) {
      newState.expandedKeys = props.autoExpandParent ? (0, _util.calcExpandedKeys)(props.expandedKeys, props) : props.expandedKeys;
    }

    if (checkSync('selectedKeys')) {
      newState.selectedKeys = (0, _util.calcSelectedKeys)(props.selectedKeys, props);
    }

    if (checkSync('checkedKeys')) {
      var _ref7 = (0, _util.calcCheckedKeys)(props.checkedKeys, props) || {},
          _ref7$checkedKeys = _ref7.checkedKeys,
          _checkedKeys = _ref7$checkedKeys === undefined ? [] : _ref7$checkedKeys,
          _ref7$halfCheckedKeys = _ref7.halfCheckedKeys,
          _halfCheckedKeys = _ref7$halfCheckedKeys === undefined ? [] : _ref7$halfCheckedKeys;

      newState.checkedKeys = _checkedKeys;
      newState.halfCheckedKeys = _halfCheckedKeys;
    }

    if (checkSync('loadedKeys')) {
      newState.loadedKeys = props.loadedKeys;
    }

    if (needSync) {
      return newState;
    }
    return null;
  };

  this.setUncontrolledState = function (state) {
    var needSync = false;
    var newState = {};

    Object.keys(state).forEach(function (name) {
      if (name in _this4.props) return;

      needSync = true;
      newState[name] = state[name];
    });

    if (needSync) {
      _this4.setState(newState);
    }
  };

  this.isKeyChecked = function (key) {
    var _state$checkedKeys = _this4.state.checkedKeys,
        checkedKeys = _state$checkedKeys === undefined ? [] : _state$checkedKeys;

    return checkedKeys.indexOf(key) !== -1;
  };

  this.renderTreeNode = function (child, index) {
    var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
    var _state4 = _this4.state,
        _state4$expandedKeys = _state4.expandedKeys,
        expandedKeys = _state4$expandedKeys === undefined ? [] : _state4$expandedKeys,
        _state4$selectedKeys = _state4.selectedKeys,
        selectedKeys = _state4$selectedKeys === undefined ? [] : _state4$selectedKeys,
        _state4$halfCheckedKe = _state4.halfCheckedKeys,
        halfCheckedKeys = _state4$halfCheckedKe === undefined ? [] : _state4$halfCheckedKe,
        _state4$loadedKeys = _state4.loadedKeys,
        loadedKeys = _state4$loadedKeys === undefined ? [] : _state4$loadedKeys,
        _state4$loadingKeys = _state4.loadingKeys,
        loadingKeys = _state4$loadingKeys === undefined ? [] : _state4$loadingKeys,
        dragOverNodeKey = _state4.dragOverNodeKey,
        dropPosition = _state4.dropPosition;

    (0, _objectDestructuringEmpty3['default'])(_this4.props);

    var pos = (0, _util.getPosition)(level, index);
    var key = child.key || pos;

    return _react2['default'].cloneElement(child, {
      key: key,
      eventKey: key,
      expanded: expandedKeys.indexOf(key) !== -1,
      selected: selectedKeys.indexOf(key) !== -1,
      loaded: loadedKeys.indexOf(key) !== -1,
      loading: loadingKeys.indexOf(key) !== -1,
      checked: _this4.isKeyChecked(key),
      halfChecked: halfCheckedKeys.indexOf(key) !== -1,
      pos: pos,

      // [Legacy] Drag props
      dragOver: dragOverNodeKey === key && dropPosition === 0,
      dragOverGapTop: dragOverNodeKey === key && dropPosition === -1,
      dragOverGapBottom: dragOverNodeKey === key && dropPosition === 1
    });
  };
};

exports['default'] = Tree;